<?php

/*	LibFox - Simple library for XML-based backends.
	Copyright (C) 2008 LinFox Serviços em Informática LTDA.

	This file is part of LibFox.

	LibFox is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	LibFox is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>. */

require_once 'model.php';

/**
 * Abstract class for Data Access Objects
 * 
 * This is used to retrieve and modify entries
 * related to models in a database.
 */
abstract class dao
{
	/**
	 * The name of the column that serves as primary key.
	 *
	 * @var string
	 */
	public $key = 'id';
	/**
	 * The name of the table.
	 *
	 * @var unknown_type
	 */
	protected $table = 'models';
	/**
	 * Names of tables that have relations with the one defined in $table.
	 *
	 * Should be seperated by comma's.
	 * 
	 * @var string
	 */
	protected $tables_rel = '';
	/**
	 * Name of the model class to use.
	 *
	 * @var string
	 */
	protected $model = 'model';
	/**
	 * Database instance.
	 *
	 * @var unknown_type
	 */
	protected $db;

	/**
	 * dao's constructor
	 * 
	 * Grabs the global database instance using db::get_instance().
	 */
	public function __construct()
	{
		$this->db = db::get_instance();
	}
	
	/**
	 * Fetch a model from the database.
	 *
	 * @param string $id
	 * @return model
	 */
	public function fetch($id = 1)
	{
		$sql_fetch = '
			SELECT *
			FROM `'.$this->table.'`
			WHERE `'.$this->key.'` = "'.addslashes($id).'"';
		$result = $this->db->query($sql_fetch);
		if (!$model = $result->fetchObject($this->model)) {
			throw new Exception($this->model.'_not_found');
		}
		return $model;
	}

	/**
	 * Fetch an array with models from the database.
	 *
	 * By default this will grab _all_ item's in the table.
	 * You can controll this by using the $search parameter.
	 * 
	 * @param string $search
	 * @return array
	 */
	public function fetch_all($search = false)
	{
		$models = array();
		$sql = '
			SELECT *
			FROM `'.$this->table.'` ';
		if ($search) {
			$sql .= 'WHERE `'.$this->key.'` = "'.$search.'"';
		}
		$result = $this->db->query($sql);
		while ($model = $result->fetchObject($this->model)) {
			$models[] = $model;
		}
		return $models;
	}

	/**
	 * Fetch an empty model structure.
	 *
	 * @return model
	 */
	public function fetch_model()
	{
		$model = new $this->model();
		$sql = 'SHOW FIELDS FROM `'.$this->table.'`';
		$result = $this->db->query($sql);
		while ($column = $result->fetchObject())
		{
			$field = $column->Field;
			$model->$field = '';
		}
		return $model;
	}

	/**
	 * Create a new entry in the table.
	 * 
	 * Returns a model with the key if the created row.
	 *
	 * @return model
	 */
	public function create()
	{
		$key = $this->key;
		$sql = 'INSERT INTO `'.$this->table.'` VALUES()';
		$this->db->query($sql);
		$model = new $this->model;
		$model->$key = $this->db->lastInsertId();
		return $model;
	}

	/**
	 * Insert's a model into the database.
	 *
	 * @param model $model
	 * @return boolean
	 */
	public function insert($model)
	{
		if (get_class($model) != $this->model) {
			throw new Exception('object_of_incorrect_class');
			return false;
		}
		$sql_insert = 'INSERT INTO `'.$this->table.'` SET';
		foreach ($model as $field => $value) {
			$sql_insert .= '`'.$field.'` = "'.addslashes($value).'",';
		}
		$sql_insert = substr($sql_insert, 0, -1);
		
		if (!$this->db->query($sql_insert)) {
			throw new Exception($this->model.'_not_inserted');
			return false;
		}
		return true;
	}

	/**
	 * Update model in database.
	 *
	 * @param model $model
	 * @return boolean
	 */
	public function update($model)
	{
		$model_db = $this->fetch_model();
		if (get_class($model) != $this->model) {
			throw new Exception('object_of_incorrect_class');
			return false;
		}
		$key = $this->key;
		$sql_update = 'UPDATE `'.$this->table.'` SET';
		foreach ($model_db as $field => $value) {
			if ($field != $this->key) {
				$sql_update .= ' `'.$field.'` = "'.addslashes($model->$field).'",';
			}
		}
		$sql_update = substr($sql_update, 0, -1);
		$sql_update .= ' WHERE `'.$this->key.'` = "'.$model->$key.'" ';

		if (!$this->db->query($sql_update)) {
			throw new Exception($this->model.'_not_updated');
			return false;
		}
		return true;
	}

	/**
	 * Delete row from database.
	 *
	 * @param mixed $id
	 * @return boolean
	 */
	public function delete($id)
	{
		$sql_delete = '
			DELETE FROM `'.$this->table.'`
			WHERE `'.$this->key.'` = "'.$id.'"';
		if (!$this->db->query($sql_delete)) return false;

		if ($this->tables_rel != '') {
			$rels = explode(',',$this->tables_rel);
			foreach ($rels as $rel) {
				$sql_delete = '
					DELETE FROM `'.$rel.'`
					WHERE `'.$this->key.'` = "'.addslashes($id).'"';
				if (!$this->db->query($sql_delete)) return false;
			}
		}
		return true;
	}

	/**
	 * Replaces \r in a string with \n
	 *
	 * @param string $string
	 * @return string
	 */
	protected function str_clean($string)
	{
		return str_replace('\r','\n',$string);
	}

}

?>
